/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package weka.attributeSelection.semiAS.semiClusterAS;

import java.util.Arrays;

/**
 *
 * @author Administrator
 */
public class KMeansForSemiAS extends ClusterForSemiAS {
    
    public KMeansForSemiAS(int[] indicator, final double[][] distance, int numAttribs, int numCluster) {
        super(indicator, distance, numAttribs, numCluster);
    }

    public void run() {
        int[] center = new int[m_numCluster];
        int[] preCenter = new int[m_numCluster];

        int iCluster = 0;
        for (int i = 0; i < m_numAttribs - 1; i++) {
            if (m_indicator[i] == -1) {
                continue;
            }
            if (iCluster < m_numCluster) {
                center[iCluster] = i;
                iCluster++;
            }
        }

        do {
            KMeans(center);
            preCenter = center.clone();
            updateCenter(center);
        } while (!Arrays.equals(center, preCenter));
    }

    private void KMeans(final int[] center) {
        for (int i = 0; i < m_numAttribs - 1; i++) {//聚类中心距离自身最近
            if (m_indicator[i] == -1) {
                continue;
            }
            double minDis = m_distance[i][center[0]];
            int minClsIdx = 0;
            for (int c = 1; c < center.length; c++) {
                if (m_distance[i][center[c]] < minDis) {
                    minDis = m_distance[i][center[c]];
                    minClsIdx = c;
                }
            }
            m_indicator[i] = minClsIdx + 1;

        }
        for (int j = 0; j < center.length; j++) {
            m_indicator[center[j]] = j + 1;
        }
    }

    private void updateCenter(int[] center) {
        int n = center.length;
        boolean[] flag = new boolean[n];
        double[] minDisSum = new double[n];

        for (int i = 0; i < m_numAttribs - 1; i++) {
            if (m_indicator[i] == -1) {
                continue;
            }
            int c = m_indicator[i] - 1;
            double disSum = calDisAve(i);
            if (flag[c] == false) {
                minDisSum[c] = disSum;
                center[c] = i;
                flag[c] = true;
            } else {
                if (disSum < minDisSum[c]) {
                    minDisSum[c] = disSum;
                    center[c] = i;
                }
            }
        }
    }

        private double calDisAve(int i) {
        double disAve = 0.0;
        int c = m_indicator[i] - 1;
        int n = 0;
        for (int j = 0; j < m_distance.length; j++) {
            if (j == i) {
                continue;
            }
            if (m_indicator[j] - 1 == c) {
                disAve = disAve + m_distance[i][j];
                n++;
            }
        }
        return disAve / n;
    }

}
